/*
 * duybRedux
 * ========================================
 * @Author: Duyb
 * @Date: 2022-03-01 18:35:41
 * @Last Modified by: Duyb
 * @Last Modified time: 2022-03-02 21:38:09
 */

/**
 *
 * @param {Function} reducer - 根据 action 的类型，更改 store 中的状态
 * @param {any} [preloadedState] - 预存储的 store 状态
 * @param {Function} [enhancer] - 对 store 的功能进行增强
 *
 * @returns {Store} - Redux Store 对象 { getState, dispatch, subscribe }
 */
function createStore(reducer, preloadedState, enhancer) {
  // 约束 reducer 参数类型
  if (typeof reducer !== 'function') {
    throw new Error('reducer 必须是函数');
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('enhancer 必须是函数');
    }

    return enhancer(createStore)(reducer, preloadedState);
  }

  // store 对象中存储的状态
  let currentState = preloadedState;
  // 存放订阅者函数
  const currentListeners = [];

  // 获取状态
  function getState() {
    return currentState;
  }

  // 触发 action
  function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error('action 必须是对象');
    }
    if (typeof action.type === 'undefined') {
      throw new Error('action 对象必须要有 type 属性');
    }

    currentState = reducer(currentState, action);
    // 循环数组，调用订阅者
    for (let i = 0; i < currentListeners.length; i++) {
      const listener = currentListeners[i];
      listener();
    }
  }

  // 订阅状态
  function subscribe(listener) {
    currentListeners.push(listener);
  }

  return {
    getState,
    dispatch,
    subscribe,
  };
}

// 中间件函数
function applyMiddleware(...middlewares) {
  return function (createStore) {
    return function (reducer, preloadedState) {
      // 创建 store
      const store = createStore(reducer, preloadedState);
      // 阉割版的 store
      const middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch,
      };

      // 调用中间件的第一层函数，传递阉割版的 store 对象
      const chain = middlewares.map((middleware) => middleware(middlewareAPI));
      const dispatch = compose(...chain)(store.dispatch);

      return {
        ...store,
        dispatch,
      };
    };
  };
}

function compose() {
  const funcs = [...arguments];
  console.log('funcs :', funcs);

  return function (dispatch) {
    for (let i = funcs.length - 1; i >= 0; i--) {
      dispatch = funcs[i](dispatch);
    }

    return dispatch;
  };
}

function bindActionCreators(actionCreators, dispatch) {
  const boundActionCreators = {};

  for (const key in actionCreators) {
    boundActionCreators[key] = function () {
      dispatch(actionCreators[key]());
    };
  }

  return boundActionCreators;
}

function combineReducers(reducers) {
  // 1. 检测 reducer 类型，必须是函数
  const reducerKeys = Object.keys(reducers);
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i];
    if (typeof reducers[key] !== 'function') {
      throw new Error('reducer 必须是函数');
    }
  }

  // 2. 调用一个一个的小的 reducer ，将每一个小的 reducer 中返回的状态存储在一个新的大的对象中
  return function (state, action) {
    const nextState = {};

    for (let i = 0; i < reducerKeys.length; i++) {
      const key = reducerKeys[i];
      const reducer = reducers[key];
      const previousStateForKey = state[key];

      nextState[key] = reducer(previousStateForKey, action);
    }

    console.log('combineReducers nextState :', nextState);
    return nextState;
  };
}

// 判断 obj 参数是否是对象
function isPlainObject(obj) {
  // 排除基本数据类型和null
  if (typeof obj !== 'object' || obj === null) return false;

  // 区分数组和对象，原型对象对比的方式
  let proto = obj;
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto);
  }

  return Object.getPrototypeOf(obj) === proto;
}
